I can make my ticking clock, but now I have another problem. Even using the LED multiplexing circuit I still need to use 12 precious pins of my PICmicro to drive the display. If I want to add stop, start and reset buttons to my stop watch I need to use a bigger PICmicro with more pins. However, I am a naturally cheap person, and so I started to think about ways round this.
If you are using the PICmicro development board you will notice that the switches are still there. These can be used to provide inputs to the ports, but because the ports are configured as inputs the PICmicro will not read them. We know that we can change the mode of the pins under software control, so it occurred to me that it might be possible to change a port into read mode, read the pins and store them, and then flip the port back into output mode. This will only take a handful of statements and should happen so quickly that the display will not flicker at all.
If you look at the program snippet alongside you will see that the refresh function now switches PORTB into input mode, copies it into a variable and then flips it back into output mode again. The only thing which is important is that, before you set the PORTB
into input you must clear all the output bits. If you don't, because of the
way that the PORT
is latched onto the outputs, you will read back invalid data.
Other Cunning People
If you press a button in PORTB while Exercise 4.6 is running you will notice that, because the buttons try to pull the signal high, while the PICmicro is pulling the signal low, the particular segment controlled by that bit will dim slightly. This is inevitable, but will not do any damage to the circuitry since all the current flows are limited.
I have noticed this behaviour on other devices with input switches and LEDs. Previously I assumed that the circuit designers were not very good at their jobs, and had not properly wired the inputs and the outputs However, it now occurs to me that these designers are actually quite clever people, since they are probably using the same trick we are.
Anyway, this means that we are now able to read from ports which are being used to drive the LEDs, provided that my foreground program reads from the global variable PORTB, rather than the actual hardware port.
unsigned char PORTBinputs ;
/* each time refresh is called it */
/* sets the display for a led and */
/* moves on to the next */
void refresh ( void )
{
/* turn off all the LEDs */
PORTA = 0 ;
/* now read port b */
/* set to 0 so we can read it */
PORTB = 0 ;
/* set pins 0-7 of PORTB for input*/
TRISB = 0xff ;
/* copy the input pins */
PORTBinputs = PORTB ;
/* set all of PORTB for output */
TRISB = 0x00 ;
/* now sort out the display */
/* set segments for the led */
PORTB = segments [led_counter] ) ;
/* turn the led on */
PORTA = enable [led_counter ] ;
/* move on to the next led */
led_counter = led_counter + 1 ;
/* see if we fell off the end */
if ( led_counter == DISPLAY_SIZE )
{
led_counter = 0 ;
}
}